package rensoft.android.view;

import static rensoft.java.lang.Lang.info;
import static rensoft.java.lang.Lang.is;
import static rensoft.java.lang.Lang.no;

import android.view.View;
import android.widget.Toast;
import rensoft.android.HasActivity;
import rensoft.android.HasActivityPresenter;
import rensoft.android.lang.AndroidLang;
import rensoft.android.lang.IAplication;
import rensoft.android.lang.IRequest;
import rensoft.java.collections.Map;
import rensoft.java.event.Event.EventRegistration;
import rensoft.java.event.Listener;
import rensoft.java.lang.Callback;

public class RequestPresenter<RequestType extends IRequest> extends HasActivityPresenter {

  private static final String REQUEST_ID = "_request";
  private final int loadingindicatorid;
  private RequestType request;
  private Callback<RequestType> loadListener;
  private Callback<RequestType> failedListener;
  private final String id;

  public RequestPresenter(HasActivity hasActivity, String id, int loadingIndicatorId) {
    super(hasActivity);
    this.id = id;
    this.loadingindicatorid = loadingIndicatorId;
  }

  public RequestType getRequest() {
    return request;
  }

  public void sendRequest(RequestType request) {
    request.send();
    setRequest(request);
  }

  public void setFailedListener(Callback<RequestType> callback) {
    this.failedListener = callback;
  }

  public void setLoadListener(Callback<RequestType> loadListener) {
    this.loadListener = loadListener;
  }

  public void setRequest(RequestType request) {
    this.request = request;
    initializeSendingRequest();
  }

  @Override
  protected void onRestoreNonConfigurationInstance(Map<String, Object> nonConfigurationInstance) {
    super.onRestoreNonConfigurationInstance(nonConfigurationInstance);
    restoreSendingRequest(nonConfigurationInstance);
  }

  @Override
  protected void onRetainNonConfigurationInstance(Map<String, Object> nonConfigurationInstance) {
    super.onRetainNonConfigurationInstance(nonConfigurationInstance);
    nonConfigurationInstance.put(id + REQUEST_ID, request);
  }

  protected void showNotSuccessMessage() {
    IAplication application = AndroidLang.getAplication();
    String message = request.getMessageId();
    if (no(message)) return;
    Integer messageResourceId = application.getServerMessageResourceId(message);
    if (is(messageResourceId)) message = getString(messageResourceId);
    Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
  }

  private void initializeSendingRequest() {
    if (request.isDone()) {
      if (request.isLoaded()) onRequestLoaded();
    } else {
      setLoadingVisible(true);
      final EventRegistration loadedRegistration =
          listenOnce(request.eventLoaded(), new Listener<Void>() {
            public void onEvent(EventRegistration registration, Void arg) {
              onRequestLoaded();
            }
          });
      listenOnce(request.eventDone(), new Listener<Void>() {
        public void onEvent(EventRegistration registration, Void arg) {
          onRequestDone(loadedRegistration);
        }
      });
      listenOnce(request.eventFailed(), new Listener<Void>() {
        public void onEvent(EventRegistration registration, Void arg) {
          onRequestFailed();
        }
      });
    }
  }

  private void onRequestDone(final EventRegistration loadedRegistration) {
    cancel(loadedRegistration);
    setLoadingVisible(false);
    request = null;
  }

  private void onRequestFailed() {
    if (is(failedListener)) failedListener.onCall(request);
  }

  private void onRequestLoaded() {
    if (request.isSuccess()) {
      if (is(loadListener)) loadListener.onCall(request);
    } else showNotSuccessMessage();
  }

  @SuppressWarnings("unchecked")
  private void restoreSendingRequest(Map<String, Object> nonConfigurationInstance) {
    request = (RequestType) nonConfigurationInstance.value(id + REQUEST_ID);
    if (is(request)) {
      info(request);
      initializeSendingRequest();
    }
  }

  private void setLoadingVisible(boolean visible) {
    if (visible)
      getView(loadingindicatorid).setVisibility(View.VISIBLE);
    else getView(loadingindicatorid).setVisibility(View.GONE);
  }

}
